package com.auz.datagenerator.heuristics.value;

import java.util.Random;

import javax.swing.JPanel;

import com.auz.datagenerator.heuristics.value.gui.ValueHeuristicComponent;

/**
 * Probabilistic value heuristic. The  movement is firstly considered when
 * generating the value; upon generating a movement (negative or positive),
 * the probability of generating the inverse movement is reduced by a certain
 * value, thus increasing the chance of getting consecutive identical movements.
 * The value of the movement is generated pseudo-randomly, with a generated value of at 
 * most a certain percentage of the base value.
 * @author Aurelien Bonnel
 */
public class MomentumValueHeuristic extends AbstractValueHeuristic<Double> {
	
	/**
	 * The default minimum probability
	 */
	public final double MIN_OFFSET = 0.25;
	/**
	 * The default percentage in probability change
	 */
	public final double MAX_PERCENTAGE_CHANGE = 0.02;
	private double offset = 0.05, cumulation = 0;
	private Random rnd;
	
	/**
	 * Constructor
	 * @param _base - the base value
	 */
	public MomentumValueHeuristic(double _base) {
		super(_base);
	}

	/**
	 * Returns the GUI component associated with this heuristic
	 * @return the GUI component associated with this heuristic
	 */
	public JPanel fetchGUIComponent() {
		component = new ValueHeuristicComponent(this, "Momentum offset (%)");
		component.configureSlider(0, 10, 5, 1, 5);
		component.pack();
		return component;
	}

	/**
	 * Returns the value associated with this heuristic
	 * @return the value
	 */
	public Double getValue() {
		// Calculation of direction based on momentum
		rnd = new Random(System.currentTimeMillis());
		double r = rnd.nextDouble();
		double direction = r * (2 - cumulation*offset) - (1 - cumulation*offset);
		cumulation = ((direction < 0) ? cumulation-1 : cumulation+1);
		double stop = MIN_OFFSET / offset;
		cumulation = ((cumulation > stop) ? stop : ((cumulation < -stop) ? -stop : cumulation));
		
		// Calculation of difference value
		rnd = new Random(System.currentTimeMillis());
		double percentageStep = rnd.nextDouble();
		
		// Regroup both elements together 
		double actualStep = base * (direction * (percentageStep % MAX_PERCENTAGE_CHANGE));
		return actualStep;
	}

	/**
	 * Sets the parameter value to the specified value
	 * @param _param - the new parameter value
	 */
	public void changeParameter(int _param) {
		offset = _param;		
	}

	/**
	 * Returns the value associated with the representational function associated to this heuristic
	 * @return the value associated with the representational function associated to this heuristic
	 */
	public Double getRepresentationalValue(double _x) {
		return 0.0;
	}

}
